﻿using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sasa.QualityTools.CodeAnalysis.Core.Models;
using System.IO;

namespace Sasa.QualityTools.CodeAnalysis.Core.Tests.Unit.Models
{
    [TestFixture]
    public class CodeMetricsCalculatorTest
    {
        private static readonly string MetricsPath
            = Path.Combine(Environment.GetEnvironmentVariable("PROGRAMFILES"), "Microsoft Visual Studio 10.0", "Team Tools", "Static Analysis Tools", "FxCop", "Metrics.exe");

        private static readonly string ResourceDir = Path.Combine(Environment.CurrentDirectory, "Resources", "Models", "CodeMetricsCalculator");

        private static readonly string OutputPath = Path.Combine(Environment.CurrentDirectory, Constants.CodeMetricsReportFileName);

        private CodeMetricsCalculator testee;


        [SetUp]
        public void SetUp()
        {
            testee = new CodeMetricsCalculator();
        }

        [TestCase(null)]
        [TestCase("")]
        [TestCase(" ")]
        public void PerformShouldThrowExceptionWhenMetricsPathIsNotValid(string metricsPath)
        {
            testee.CommandPath = metricsPath;
            testee.CommandOption = "/f:foo.dll";
            Assert.Throws<InvalidOperationException>(() => testee.PerformCodeAnalysis());
        }

        [TestCase(null)]
        [TestCase("")]
        [TestCase(" ")]
        public void PerformShouldThrowExceptionWhenMetricsOptionIsNotValid(string metricsOption)
        {
            testee.CommandPath = "metrics.exe";
            testee.CommandOption = metricsOption;
            Assert.Throws<InvalidOperationException>(() => testee.PerformCodeAnalysis());
        }

        [Test]
        public void PerformShouldAnalyzeAssemblyCorrectly()
        {
            var targetPath = Path.Combine(ResourceDir, "TestTarget.dll");
            testee.CommandPath = MetricsPath;
            testee.CommandOption = String.Format(@"/gac /sf /igc /f:""{0}"" /o:""{1}""", targetPath, OutputPath);
            testee.PerformCodeAnalysis();

            Assert.AreEqual(18, testee.Report.MetricValues.Count);
        }

        [Test]
        [ExpectedException(typeof(CodeAnalysisException))]
        public void PerformShouldThrowExceptionWhenFxCopCmdReturnsErrorCode()
        {
            var targetPath = Path.Combine(ResourceDir, "noexist.dll");
            testee.CommandPath = MetricsPath;
            testee.CommandOption = String.Format(@"/gac /sf /igc /f:""{0}"" /o:""{1}""", targetPath, OutputPath);
            testee.PerformCodeAnalysis();
        }

        [Test]
        public void PerformShouldAnalyzeAssemblyWhenReferencedAssemblyIsMissing()
        {
            var targetPath = Path.Combine(ResourceDir, "ReferenceError", "TestTarget.ReferenceError.dll");
            testee.CommandPath = MetricsPath;
            testee.CommandOption = String.Format(@"/gac /sf /igc /f:""{0}"" /o:""{1}""", targetPath, OutputPath);
            testee.ReferenceAssemblyPaths.Add(Path.Combine(ResourceDir, "TestTarget.dll"));

            testee.PerformCodeAnalysis();

            Assert.AreEqual(4, testee.Report.MetricValues.Count);
        }
    }
}
